using System;
using System.Collections.Generic;

namespace HEFramework
{
    /// <summary>
    ///
    /// 系统类型
    /// 
    /// ----------------------------------------
    /// 作者 hep
    /// 创建时间：2023-12-12 09:59:55
    /// ----------------------------------------
    /// </summary>
    public class TypeSystems
    {
        public class OneTypeSystems
        {
            public readonly UnOrderMultiMap_List<Type, object> mapList = new();

            // 这里不用hash，数量比较少，直接for循环速度更快
            public readonly bool[] QueueFlag;

            public OneTypeSystems(int _count)
            {
                this.QueueFlag = new bool[_count];
            }
        }

        private readonly int count;
        private readonly Dictionary<Type, OneTypeSystems> typeSystemsMap = new();

        public TypeSystems(int _count)
        {
            this.count = _count;
        }


        public OneTypeSystems GetOrCreateOneTypeSystems(Type _type)
        {
            OneTypeSystems systems = null;
            this.typeSystemsMap.TryGetValue(_type, out systems);
            if (systems != null)
            {
                return systems;
            }

            systems = new OneTypeSystems(this.count);
            this.typeSystemsMap.Add(_type, systems);
            return systems;
        }

        public OneTypeSystems GetOneTypeSystems(Type _type)
        {
            OneTypeSystems systems = null;
            this.typeSystemsMap.TryGetValue(_type, out systems);
            return systems;
        }

        public List<object> GetSystems(Type _type, Type _systemType)
        {
            OneTypeSystems oneTypeSystems = null;
            if (!this.typeSystemsMap.TryGetValue(_type, out oneTypeSystems))
            {
                return null;
            }

            if (!oneTypeSystems.mapList.TryGetValue(_systemType, out List<object> systems))
            {
                return null;
            }

            return systems;
        }
    }


    /// <summary>
    ///
    /// 系统管理器
    /// 
    /// ----------------------------------------
    /// 作者 hep
    /// 创建时间：2023-12-12 10:02:33
    /// ----------------------------------------
    /// </summary>
    [Code]
    public class SystemOwner : Singleton<SystemOwner>, ISingletonAwake
    {
        public TypeSystems TypeSystems { get; private set; }

        public void Awake()
        {
            //将实体与对应标记的系统绑定
            this.TypeSystems = new TypeSystems(InstanceQueueIndex.Max);
            foreach (Type type in CodeOwner.Instance.GetTypes(typeof(EntitySystemAttribute)))
            {
                object obj = Activator.CreateInstance(type);

                if (obj is ISystemType iSystemType)
                {
                    //iSystemType.Type == 实体类型
                    TypeSystems.OneTypeSystems oneTypeSystems = this.TypeSystems.GetOrCreateOneTypeSystems(iSystemType.Type());
                    oneTypeSystems.mapList.Add(iSystemType.SystemType(), obj);
                    int index = iSystemType.GetInstanceQueueIndex();
                    if (index > InstanceQueueIndex.None && index < InstanceQueueIndex.Max)
                    {
                        oneTypeSystems.QueueFlag[index] = true;
                    }
                }
            }
        }

        public void Serialize(Entity _entity)
        {
            if (_entity is not ISerialize)
            {
                return;
            }

            List<object> iSerializeSystems = this.TypeSystems.GetSystems(_entity.GetType(), typeof(ISerializeSystem));
            if (iSerializeSystems == null)
            {
                return;
            }

            foreach (ISerializeSystem serializeSystem in iSerializeSystems)
            {
                if (serializeSystem == null)
                {
                    continue;
                }

                try
                {
                    serializeSystem.Run(_entity);
                }
                catch (Exception e)
                {
                    Log.Error(e);
                }
            }
        }

        public void Deserialize(Entity _entity)
        {
            if (_entity is not IDeserialize)
            {
                return;
            }

            List<object> iDeserializeSystems = this.TypeSystems.GetSystems(_entity.GetType(), typeof(IDeserializeSystem));
            if (iDeserializeSystems == null)
            {
                return;
            }

            foreach (IDeserializeSystem deserializeSystem in iDeserializeSystems)
            {
                if (deserializeSystem == null)
                {
                    continue;
                }

                try
                {
                    deserializeSystem.Run(_entity);
                }
                catch (Exception e)
                {
                    Log.Error(e);
                }
            }
        }

        public void GetChild(Entity _parent, Entity _child)
        {
            List<object> iGetChildSystems = this.TypeSystems.GetSystems(_parent.GetType(), typeof(IGetChildSystem));
            if (iGetChildSystems == null)
            {
                return;
            }

            foreach (IGetChildSystem getChildSystem in iGetChildSystems)
            {
                if (getChildSystem == null)
                {
                    continue;
                }

                try
                {
                    getChildSystem.Run(_parent, _child);
                }
                catch (Exception e)
                {
                    Log.Error(e);
                }
            }
        }

        public void AddChild(Entity _parent, Entity _child)
        {
            List<object> iAddChildSystems = this.TypeSystems.GetSystems(_parent.GetType(), typeof(IAddChildSystem));
            if (iAddChildSystems == null)
            {
                return;
            }

            foreach (IAddChildSystem addChildSystem in iAddChildSystems)
            {
                if (addChildSystem == null)
                {
                    continue;
                }

                try
                {
                    addChildSystem.Run(_parent, _child);
                }
                catch (Exception e)
                {
                    Log.Error(e);
                }
            }
        }

        public void Awake(Entity _entity)
        {
            List<object> iAwakeSystems = this.TypeSystems.GetSystems(_entity.GetType(), typeof(IAwakeSystem));
            if (iAwakeSystems == null)
            {
                return;
            }

            foreach (IAwakeSystem aAwakeSystem in iAwakeSystems)
            {
                if (aAwakeSystem == null)
                {
                    continue;
                }

                try
                {
                    aAwakeSystem.Run(_entity);
                }
                catch (Exception e)
                {
                    Log.Error(e);
                }
            }
        }

        public void Awake<P1>(Entity _entity, P1 _p1)
        {
            if (_entity is not IAwake<P1>)
            {
                return;
            }

            List<object> iAwakeSystems = this.TypeSystems.GetSystems(_entity.GetType(), typeof(IAwakeSystem<P1>));
            if (iAwakeSystems == null)
            {
                return;
            }

            foreach (IAwakeSystem<P1> aAwakeSystem in iAwakeSystems)
            {
                if (aAwakeSystem == null)
                {
                    continue;
                }

                try
                {
                    aAwakeSystem.Run(_entity, _p1);
                }
                catch (Exception e)
                {
                    Log.Error(e);
                }
            }
        }

        public void Awake<P1, P2>(Entity _entity, P1 _p1, P2 _p2)
        {
            if (_entity is not IAwake<P1, P2>)
            {
                return;
            }

            List<object> iAwakeSystems = this.TypeSystems.GetSystems(_entity.GetType(), typeof(IAwakeSystem<P1, P2>));
            if (iAwakeSystems == null)
            {
                return;
            }

            foreach (IAwakeSystem<P1, P2> aAwakeSystem in iAwakeSystems)
            {
                if (aAwakeSystem == null)
                {
                    continue;
                }

                try
                {
                    aAwakeSystem.Run(_entity, _p1, _p2);
                }
                catch (Exception e)
                {
                    Log.Error(e);
                }
            }
        }

        public void Awake<P1, P2, P3>(Entity _entity, P1 p1, P2 p2, P3 p3)
        {
            if (_entity is not IAwake<P1, P2, P3>)
            {
                return;
            }

            List<object> iAwakeSystems = this.TypeSystems.GetSystems(_entity.GetType(), typeof(IAwakeSystem<P1, P2, P3>));
            if (iAwakeSystems == null)
            {
                return;
            }

            foreach (IAwakeSystem<P1, P2, P3> aAwakeSystem in iAwakeSystems)
            {
                if (aAwakeSystem == null)
                {
                    continue;
                }

                try
                {
                    aAwakeSystem.Run(_entity, p1, p2, p3);
                }
                catch (Exception e)
                {
                    Log.Error(e);
                }
            }
        }

        public void Destroy(Entity _entity)
        {
            if (_entity is not IDestroy)
            {
                return;
            }

            List<object> iDestroySystems = this.TypeSystems.GetSystems(_entity.GetType(), typeof(IDestroySystem));
            if (iDestroySystems == null)
            {
                return;
            }

            foreach (IDestroySystem iDestroySystem in iDestroySystems)
            {
                if (iDestroySystem == null)
                {
                    continue;
                }

                try
                {
                    iDestroySystem.Run(_entity);
                }
                catch (Exception e)
                {
                    Log.Error(e);
                }
            }
        }
    }
}